package gwtappcontainer.server.apis.admin;

import static com.googlecode.objectify.ObjectifyService.ofy;
import gwtappcontainer.server.DatastoreNamespaces;
import gwtappcontainer.server.apps.APIException;
import gwtappcontainer.shared.apis.APIResponse.Status;
import gwtappcontainer.shared.apis.admin.UserProp;

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.datastore.ReadPolicy.Consistency;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Ref;

class UserRepository {
	static {
		ObjectifyService.factory().register(UserEntity.class);
		ObjectifyService.factory().register(RoleEntity.class);	
	}
	
	private static final String NAMESPACE = DatastoreNamespaces.ADMIN;
	
	UserProp addUser(String email) {
							
		//email should not be already present
		UserProp prop = getUserByEmail(email);
		if (null != prop) {
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"User [" + email + "] is already present with id [" + prop.id + "]");						
		}
		
		UserEntity entity = new UserEntity();
		entity.email = email.toLowerCase();
		
		NamespaceManager.set(NAMESPACE);
		ofy().save().entity(entity).now();
		
		return entity.toProp();				
	}
	
	UserProp getUserByEmail(String email) {
		NamespaceManager.set(NAMESPACE);
		
		UserEntity entity = ofy().consistency(Consistency.STRONG).load().type(UserEntity.class).
				filter("email", email.toLowerCase()).first().get();
				
		UserProp prop = null;
		if (null != entity)
			prop = entity.toProp();
		
		return prop;
	}
	
	List<UserProp> getAllUsers() {
	
		NamespaceManager.set(NAMESPACE);
		
		List<UserEntity> entities = ofy().consistency(Consistency.STRONG).load().type(UserEntity.class).list();		
		List<UserProp> props = new ArrayList<UserProp>();
		
		for (UserEntity e : entities) {
			props.add(e.toProp());
		}
		
		return props;				
	}
	
	
	UserProp changeUserPermission(String email, String role,  boolean assign) {
		
		NamespaceManager.set(NAMESPACE);
		
		email = email.toLowerCase();
		role = role.toUpperCase();
		
		UserEntity userEntity = getUserEntity(email);
		
		if (null == userEntity) {
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Could not find user with email [" + email + "]");			
		}
		
		RoleEntity roleEntity = new RoleRepository().getRoleEntity(role);
		
		if (null == roleEntity) {
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Could not find role [" + role + "]");			
		}
			
		if (null == userEntity.roles)
			userEntity.roles = new ArrayList<Ref<RoleEntity>>();
			
		int matchingIndex = -1;
		boolean alreadyAssigned = false;
		for (int i = 0; i < userEntity.roles.size(); i++) {
			if (role.endsWith(userEntity.roles.get(i).get().name)) {
				alreadyAssigned = true;
				matchingIndex = i;
			}
		}
				
		if (assign && alreadyAssigned) {	
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"role [" + role + "] is already assigned to user [" + email + "]");			
		}
		
		if (!assign && !alreadyAssigned) {
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"role [" + role + "] is not assigned to user [" + email + "]");			
		}
		
		if (assign) {						
			userEntity.roles.add(Ref.create(roleEntity));			
		} else {						
			userEntity.roles.remove(matchingIndex);									
		}	
		
		ofy().save().entity(userEntity).now();
						
		return userEntity.toProp();	
	}

	
	private UserEntity getUserEntity(String email) {
		email = email.toLowerCase();
		NamespaceManager.set(NAMESPACE);
		
		List<UserEntity> all = ofy().load().type(UserEntity.class).list();
				
		for (UserEntity entity : all) {
			if (entity.email.equals(email)) {
				return entity;
			}
		}
		
		return null;	
	}
}
